import axios from "axios";
import { z } from "zod";
import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";

import { env } from "~/env.mjs";
import {
  data as mockCveData,
  mockVulnerabilitySummaryData,
} from "~/utils/mock/cve"; //mock data
import { hostRouter } from "./host";
import {
  type AggregatedVulnerability,
  type VulnerabilityAggregationResponse,
} from "~/types/vulnerabilityTypes";
import { getMockHosts, hasMockHosts } from "./shared-mock-data";

// Create an axios instance
const httpClient = axios.create({
  baseURL: env.SIRIUS_API_URL,
  timeout: 25000,
});

export type SiriusVulnerability = {
  vid: string;
  cvss: number;
  title: string;
  description: string;
  severity: string;
  cve: CveItem;
};

export interface NVDResponse {
  resultsPerPage: number;
  startIndex: number;
  totalResults: number;
  format: string;
  version: string;
  timestamp: string;
  vulnerabilities: DefCVEItem[];
}

export interface DefCVEItem {
  cve: CveItem;
}

export interface CveItem {
  id: string;
  sourceIdentifier: string;
  vulnStatus: string;
  published: string;
  lastModified: string;
  evaluatorComment?: string;
  evaluatorSolution?: string;
  evaluatorImpact?: string;
  cisaExploitAdd?: string;
  cisaActionDue?: string;
  cisaRequiredAction?: string;
  cisaVulnerabilityName?: string;
  cveTags?: CveTag[];
  descriptions: LangString[];
  references: Reference[];
  metrics?: Metrics;
  weaknesses?: Weakness[];
  configurations?: Config[];
  vendorComments?: VendorComment[];
}

export interface CveTag {
  sourceIdentifier: string;
  tags: string[];
}

export interface LangString {
  lang: string;
  value: string;
}

export interface Reference {
  url: string;
  source?: string;
  tags?: string[];
}

export interface Metrics {
  cvssMetricV40?: CvssV40[];
  cvssMetricV31?: CvssV31[];
  cvssMetricV30?: CvssV30[];
  cvssMetricV2?: CvssV2[];
}

export interface CvssV40 {
  source: string;
  type: string;
  cvssData: CvssDataV40;
}

export interface CvssV31 {
  source: string;
  type: string;
  cvssData: CvssDataV31;
  exploitabilityScore?: number;
  impactScore?: number;
}

export interface CvssV30 {
  source: string;
  type: string;
  cvssData: CvssDataV30;
  exploitabilityScore?: number;
  impactScore?: number;
}

export interface CvssV2 {
  source: string;
  type: string;
  cvssData: CvssDataV2;
  baseSeverity?: string;
  exploitabilityScore?: number;
  impactScore?: number;
  acInsufInfo?: boolean;
  obtainAllPrivilege?: boolean;
  obtainUserPrivilege?: boolean;
  obtainOtherPrivilege?: boolean;
  userInteractionRequired?: boolean;
}

export interface CvssDataV40 {
  version: string;
  vectorString: string;
}

export interface CvssDataV31 {
  version: string;
  vectorString: string;
  baseScore: number;
  baseSeverity: string;
  attackVector: string;
  attackComplexity: string;
  privilegesRequired: string;
  userInteraction: string;
  scope: string;
  confidentialityImpact: string;
  integrityImpact: string;
  availabilityImpact: string;
}

export interface CvssDataV30 {
  version: string;
  vectorString: string;
  baseScore: number;
  baseSeverity: string;
  attackVector: string;
  attackComplexity: string;
  privilegesRequired: string;
  userInteraction: string;
  scope: string;
  confidentialityImpact: string;
  integrityImpact: string;
  availabilityImpact: string;
}

export interface CvssDataV2 {
  version: string;
  vectorString: string;
  baseScore: number;
  accessVector: string;
  accessComplexity: string;
  authentication: string;
  confidentialityImpact: string;
  integrityImpact: string;
  availabilityImpact: string;
}

export interface Weakness {
  source: string;
  type: string;
  description: LangString[];
}

export interface Config {
  operator: string;
  negate?: boolean;
  nodes: Node[];
}

export interface Node {
  operator: string;
  negate?: boolean;
  cpeMatch?: CpeMatch[];
}

export interface CpeMatch {
  vulnerable: boolean;
  criteria: string;
  matchCriteriaId: string;
  versionStartExcluding?: string;
  versionStartIncluding?: string;
  versionEndExcluding?: string;
  versionEndIncluding?: string;
}

export interface VendorComment {
  organization: string;
  comment: string;
  lastModified: string;
}

export interface VulnerabilitySummary {
  vid: string;
  riskScore: number;
  description: string;
  published: string;
  severity: "informational" | "low" | "medium" | "high" | "critical";
  hostCount: number;
}

// Simple vulnerability interface matching the API response
export interface SimpleVulnerability {
  vid: string;
  title: string;
  hostCount: number;
  description: string;
  riskScore: number;
}

export const vulnerabilityRouter = createTRPCRouter({
  // Retrieve a single vulnerability data
  getVulnerability: publicProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ input }) => {
      let { id } = input;
      try {
        if (!id) {
          throw new Error("No ID provided");
        }
        console.log("ID:", id);

        id = id.trim();
        if (!id.toUpperCase().startsWith("CVE-")) {
          id = `CVE-${id}`;
        }
        id = id.toUpperCase();

        const response = await httpClient.get<CveItem>(`vulnerability/${id}`);
        const vuln = response.data;

        //Mock data
        // return mockCveItem;

        return vuln ?? null;
      } catch (error) {
        // Handle the error accordingly
        console.error("Error fetching host: vulnerability.ts");
        // console.error(error);
        return null;
      }
    }),

  // Retrieve all vulnerabilities from the API
  getAllVulnerabilities: publicProcedure.query(async () => {
    try {
      // Direct call to the vulnerability endpoint
      const response = await httpClient.get<SimpleVulnerability[]>(
        "host/vulnerabilities/all"
      );

      // Extract vulnerabilities from response
      const vulns = response.data || [];

      // Calculate severity counts based on risk scores
      const counts = {
        total: vulns.length,
        critical: 0,
        high: 0,
        medium: 0,
        low: 0,
        informational: 0,
      };

      // Count vulnerabilities by severity based on risk score
      vulns.forEach((vuln) => {
        const severity = determineSeverity(vuln.riskScore);
        counts[severity]++;
      });

      // Return simplified response structure
      return {
        vulnerabilities: vulns,
        counts,
      };
    } catch (error) {
      console.error("Error fetching vulnerabilities:", error);
      // Return empty response on error
      return {
        vulnerabilities: [],
        counts: {
          total: 0,
          critical: 0,
          high: 0,
          medium: 0,
          low: 0,
          informational: 0,
        },
      };
    }
  }),
});

// Helper function to determine severity from risk score
function determineSeverity(riskScore: number): keyof typeof counts {
  if (riskScore >= 9.0) return "critical";
  if (riskScore >= 7.0) return "high";
  if (riskScore >= 4.0) return "medium";
  if (riskScore > 0) return "low";
  return "informational";
}

export const mockCveItem: CveItem = {
  id: "CVE-2019-1010218",
  sourceIdentifier: "josh@bress.net",
  published: "2019-07-22T18:15:10.917",
  lastModified: "2024-11-21T04:18:03.857",
  vulnStatus: "Modified",

  // cveTags is an empty array from your JSON
  cveTags: [],

  // Two descriptions in English and Spanish
  descriptions: [
    {
      lang: "en",
      value:
        "Cherokee Webserver Latest Cherokee Web server Upto Version 1.2.103 (Current stable) is affected by: Buffer Overflow - CWE-120. The impact is: Crash. The component is: Main cherokee command. The attack vector is: Overwrite argv[0] to an insane length with execl. The fixed version is: There's no fix yet.",
    },
    {
      lang: "es",
      value:
        "El servidor web de Cherokee más reciente de Cherokee Webserver Hasta Versión 1.2.103 (estable actual) está afectado por: Desbordamiento de Búfer - CWE-120. El impacto es: Bloqueo. El componente es: Comando cherokee principal. El vector de ataque es: Sobrescribir argv[0] en una longitud no sana con execl. La versión corregida es: no hay ninguna solución aún.",
    },
  ],

  // Metrics: v3.1 and v2 examples
  metrics: {
    cvssMetricV31: [
      {
        source: "nvd@nist.gov",
        type: "Primary",
        cvssData: {
          version: "3.1",
          vectorString: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
          baseScore: 7.5,
          baseSeverity: "HIGH",
          attackVector: "NETWORK",
          attackComplexity: "LOW",
          privilegesRequired: "NONE",
          userInteraction: "NONE",
          scope: "UNCHANGED",
          confidentialityImpact: "NONE",
          integrityImpact: "NONE",
          availabilityImpact: "HIGH",
        },
        exploitabilityScore: 3.9,
        impactScore: 3.6,
      },
    ],
    cvssMetricV2: [
      {
        source: "nvd@nist.gov",
        type: "Primary",
        cvssData: {
          version: "2.0",
          vectorString: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
          baseScore: 5.0,
          accessVector: "NETWORK",
          accessComplexity: "LOW",
          authentication: "NONE",
          confidentialityImpact: "NONE",
          integrityImpact: "NONE",
          availabilityImpact: "PARTIAL",
        },
        baseSeverity: "MEDIUM",
        exploitabilityScore: 10.0,
        impactScore: 2.9,
        acInsufInfo: false,
        obtainAllPrivilege: false,
        obtainUserPrivilege: false,
        obtainOtherPrivilege: false,
        userInteractionRequired: false,
      },
    ],
  },

  // Weaknesses
  weaknesses: [
    {
      source: "josh@bress.net",
      type: "Secondary",
      description: [
        {
          lang: "en",
          value: "CWE-120",
        },
      ],
    },
    {
      source: "nvd@nist.gov",
      type: "Primary",
      description: [
        {
          lang: "en",
          value: "CWE-787",
        },
      ],
    },
  ],

  // Configurations
  configurations: [
    {
      // The interface requires "operator" at the top level.
      // The JSON omits it, so let's default to "AND" or "OR" as appropriate:
      operator: "AND",
      negate: false,
      nodes: [
        {
          operator: "OR",
          negate: false,
          cpeMatch: [
            {
              vulnerable: true,
              criteria:
                "cpe:2.3:a:cherokee-project:cherokee_web_server:*:*:*:*:*:*:*:*",
              versionEndIncluding: "1.2.103",
              matchCriteriaId: "DCE1E311-F9E5-4752-9F51-D5DA78B7BBFA",
            },
          ],
        },
      ],
    },
  ],

  // References
  references: [
    {
      url: "https://i.imgur.com/PWCCyir.png",
      source: "josh@bress.net",
      tags: ["Exploit", "Third Party Advisory"],
    },
    {
      url: "https://i.imgur.com/PWCCyir.png",
      source: "af854a3a-2127-422b-91ae-364da2661108",
      tags: ["Exploit", "Third Party Advisory"],
    },
  ],
};
